package es.unileon.prg2.censo.composite;

/**
 * @author Manuel Molinos Crespo, Adrian Campazas Vega, Alberto Castro Delgado, Pedro Alvarez Alvarez, Adrian Cabello Galvan, Jose Alvaro Fernandez Alvarez
 *
 */

import java.util.ArrayList;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import es.unileon.prg2.censo.adapter.ArrayListAggregate;
import es.unileon.prg2.censo.exception.CensoException;
import es.unileon.prg2.censo.handler.GenericId;
import es.unileon.prg2.censo.handler.Handler;
import es.unileon.prg2.censo.handler.ShortName;
import es.unileon.prg2.censo.iterator.*;
import es.unileon.prg2.censo.singleton.TableComprobation;

public abstract class Composite implements Component {
	static Logger logger = Logger.getLogger(Composite.class.getName());

	private ArrayList<Component> children;

	/**
	 * Constructor used to created an ArrayList where children components will
	 * be saved.
	 * 
	 * @throws CensoException
	 */
	public Composite() throws CensoException {
		this.children = new ArrayList<Component>();
		PropertyConfigurator.configure("etc/log4j.properties");
		logger.info(children+" created successfully");
	}

	/**
	 * Method used to converted the tree of components in a simple ArrayList.
	 * 
	 * @return The ArrayList with all components of the tree in a simple
	 *         ArrayList
	 * @throws CensoException
	 */
	protected void treeFlatten(ArrayListAggregate<Component> plainTree)
			throws CensoException {
		if(plainTree.isEmpty()) {
			plainTree.add(this);
		}
		for (Component c : children) {
			plainTree.add(c);
			if (c.getComposite() != null) {
				c.getComposite().treeFlatten(plainTree);
			}
		}
	}

	/**
	 * Method used to created an TreeIterator
	 * 
	 * @return The TreeIterator created before
	 * @throws CensoException 
	 */
	public Iterador createIterator() throws CensoException {
		ArrayListAggregate<Component> twoDimensions = new ArrayListAggregate<Component>();
		this.treeFlatten(twoDimensions);
		logger.info("TreeIterator created succesfully");
		return twoDimensions.createIterator();
	}

	/**
	 * Method used to created an Iterator
	 * 
	 * @param args
	 *            String with type that you want filter and two Strings with the
	 *            ages between you want. Example:
	 *            createIterator("citizens","18","20");
	 * @return The CitizenIterator created before
	 * @throws CensoException
	 */
	public Iterador createIterator(int age, int age2) throws CensoException {
		ArrayListAggregate<Component> twoDimensions = new ArrayListAggregate<Component>();
			this.treeFlatten(twoDimensions);
			logger.info("CitizenIterator created succesfully");
			return twoDimensions.createIterator(age, age2);
	}

	@Override
	public Component search(Handler id) {
		Component found = null;
		if (this.getId().compareTo(id) == 0) {
			found = this;
			logger.info(id+" found succesfully");
		} else {
			Iterator<Component> i = this.children.iterator();
			while (i.hasNext() && found == null) {
				found = i.next().search(id);
			}
		}
		return found;
	}

	@Override
	public boolean delete(Component id) throws CensoException {
		for (int i = 0; i < this.children.size(); i++) {
			if (children.remove(id)) {
				logger.info(id+" remove sucessfully");
				return true;
			} else if (this.children.get(i).getLevel() != "Citizen") {
				return this.children.get(i).delete(id);
			}
		}
		return false;
	}

	@Override
	public boolean add(Component creation) throws CensoException {
		String myLevel = getLevel();
		boolean success = TableComprobation.getInstance().comprobation(myLevel,
				creation.getLevel());
		if (success == true) {
			if (this.search(creation.getId()) == null) {
				this.children.add(creation);
				logger.info(creation + " add sucessfully");
				return true;
			} else {
				StringBuffer message = new StringBuffer();
				message.append("Object was added before.");
				if (message.length() != 0) {
					throw new CensoException(message.toString());
				}
				return false;
			}
		} else {
			StringBuffer message = new StringBuffer();
			message.append("Object can't add other object.");
			if (message.length() != 0) {
				throw new CensoException(message.toString());
			}
			return false;
		}
	}

	@Override
	public int size() throws CensoException {
		int size = 0;
		for (Component c : this.children) {
			size += c.size();
		}
		logger.info("The number of component of the list is " + size);
		logger.info("Size successfully ");
		return size;
	}

	@Override
	public String toString() {
		StringBuffer output = new StringBuffer();
		String finisher = "";
		for (Component c : this.children) {
			output.append(c.toString());
		}
		finisher = output.toString();
		logger.info("Convert to String successfully ");
		return finisher;

	}

	@Override
	public Composite getComposite() {
		return this;
	}

	@Override
	public ArrayList<Component> getChildren() {
		return this.children;
	}
}
